import CryptoWorker from "./worker.js?worker"
import dayjs from "dayjs"
import "dayjs/locale/zh-cn"
dayjs.locale("zh-cn")

export function createWorker(code, params = {}, timeout = 60000) {
    return new Promise((resolve, reject) => {
        const startTime = performance.now()
        const consoleOutputs = []
        const worker = new CryptoWorker()

        const timeoutId = setTimeout(() => {
            worker.terminate()
            reject({
                error: {
                    message: "执行超时",
                    type: "TimeoutError",
                },
                params: params || {},
                consoleOutputs,
                executionTime: Math.round(performance.now() - startTime),
                timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
            })
        }, timeout)

        worker.onmessage = (event) => {
            const { type, output, error, params: workerParams } = event.data
            const executionTime = Math.round(performance.now() - startTime)
            const timestamp = dayjs().format("YYYY-MM-DD HH:mm:ss")

            switch (type) {
                case "console":
                    consoleOutputs.push(output)
                    console[output.type](`[Worker ${output.timestamp}]`, ...output.args)
                    break

                case "error":
                    clearTimeout(timeoutId)
                    worker.terminate()
                    reject({
                        error: error || {},
                        params: workerParams || {},
                        consoleOutputs: consoleOutputs.map((output) => ({
                            ...output,
                            args: output.args.map((arg) => String(arg)),
                        })),
                        executionTime,
                        timestamp,
                    })
                    break

                case "complete":
                    clearTimeout(timeoutId)
                    worker.terminate()
                    if (event.data.status === "error") {
                        reject({
                            error: event.data.error || {},
                            params: workerParams || {},
                            consoleOutputs: consoleOutputs.map((output) => ({
                                ...output,
                                args: output.args.map((arg) => String(arg)),
                            })),
                            executionTime,
                            timestamp,
                        })
                    } else {
                        resolve({
                            params: workerParams || {},
                            error: null,
                            consoleOutputs: consoleOutputs.map((output) => ({
                                ...output,
                                args: output.args.map((arg) => String(arg)),
                            })),
                            executionTime,
                            timestamp,
                        })
                    }
                    break
            }
        }

        worker.onerror = (error) => {
            clearTimeout(timeoutId)
            worker.terminate()

            reject({
                error: {
                    message: error.message,
                    type: "WorkerError",
                    stack: error.error?.stack || null,
                    lineNumber: error.lineno,
                    columnNumber: error.colno,
                },
                params: {},
                consoleOutputs,
                executionTime: Math.round(performance.now() - startTime),
                timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
            })
        }

        worker.postMessage({ code, initParams: params })
    })
}
